package m.server.web;

import com.alibaba.fastjson.JSONObject;
import m.common.action.RequestParam;
import m.server.ServerHandler;
import m.server.web.req.Header;
import m.server.web.req.RequestExecption;
import m.server.web.res.ResponseByte;
import m.server.web.res.ResponseFile;
import m.server.web.res.StatusCode;
import m.system.RuntimeData;
import m.system.db.TransactionManager;
import m.system.url.UrlMarker;
import m.system.util.ActionUtil;
import m.system.util.DateUtil;
import m.system.util.StringUtil;
import m.system.util.SystemUtil;

import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.util.Date;

public class WebHandler extends ServerHandler {
    public WebHandler(Socket socket) {
        super(socket);
    }

    @Override
    public void run() {
        Socket socket=getSocket();
        Date startDate=new Date();
        Response response=null;
        try {
            Request request =new Request(getReadBody(),socket.getLocalAddress().getHostAddress());
            response =new Response(socket.getOutputStream(), request);
            String servletPath=request.getUri();
            String basePath = request.getHeader(Header.Host);
            SystemUtil.println("-----------------------------------------------------------"
                ,"\r\n",DateUtil.format(startDate, DateUtil.YYYY_MM_DD_HH_MM_SS),"\t>>>>>\t\t","url:",basePath,servletPath);
            AuthInfoUtil.init(request);//初始化session
            if(UrlMarker.isDisabledUrl(servletPath)) {
                SystemUtil.println("Disabled url:",servletPath);
                response.out("无效地址",StatusCode.NotFound);
                return;
            }
            executeFilter(request.getUri(),request,response,null);
        } catch (Exception e) {
            String error;
            StatusCode code;
            if(e instanceof RequestExecption){
                RequestExecption re=(RequestExecption) e;
                error=re.getMessage();
                code=re.getStatus();
            }else{
                error=e.getMessage();
                code=StatusCode.None;
                e.printStackTrace();
            }
            if(code!=StatusCode.None){
                if(null!=response) {
                    response.out(error, code);
                }else{
                    e.printStackTrace();
                }
            }
        } finally {
            AuthInfoUtil.release();
            TransactionManager.closeConnection();
            if(RuntimeData.getDebug()){
                Date endDate=new Date();
                long time=endDate.getTime()-startDate.getTime();
                SystemUtil.print(DateUtil.format(endDate, DateUtil.YYYY_MM_DD_HH_MM_SS),"\t<<<<<\t 耗时:",time);
                if(time>1000) {
                    SystemUtil.println(" 耗时超1秒 ");
                }else {
                    SystemUtil.println(" ");
                }
            }
            if(null!=response) {
                response.destroy();
            }
            try {
                socket.shutdownInput();
            } catch (Exception ignored) {}
            try {
                socket.shutdownOutput();
            } catch (Exception ignored) {}
            try {
                socket.close();
            } catch (Exception ignored) {}
        }
    }

    /**
     * 请求过滤
     */
    private void executeFilter(String servletPath,Request request,Response response, JSONObject requestBody) throws RequestExecption {
        if("/".equals(servletPath)) servletPath="/index.html";
        String serverName= StringUtil.noSpace(request.getHeader(Header.Host)).split(":")[0];
        String referer=request.getHeader(Header.Referer);
        String authorization=request.getHeader(Header.Authorization);
        if(request.isEnableUrl() || UrlMarker.isEnableUrl(serverName, servletPath, referer, authorization)){
            request.setEnableUrl(true);
            SystemUtil.println("\t referer:",referer,
                "\r\n\t Authorization:",authorization);
        }else {
            SystemUtil.println("Disabled url!",
                "\r\n\t referer:",referer,
                "\r\n\t Authorization:",authorization);
            throw new RequestExecption(StatusCode.Unauthorized,"无权访问");
        }
        Object result=null;
        String redirectPath=UrlMarker.getRedirectUrl(servletPath);
        if(null!=redirectPath){
            if(redirectPath.indexOf("/")!=0) redirectPath="/"+redirectPath;
            SystemUtil.print("--------redirect:",redirectPath);
            if(redirectPath.contains("?")) {
                if(null==requestBody) requestBody=new JSONObject();
                int idx=redirectPath.indexOf("?");
                requestBody.putAll(Request.urlParamToJSON(redirectPath.substring(idx+1)));
                redirectPath=redirectPath.substring(0,idx);
            }
            executeFilter(redirectPath,request,response,requestBody);
            return;
        }
        if(servletPath.length()>1){
            RequestParam rp=ActionUtil.getRequestParamList(servletPath);
            if(null!=rp) {//action请求
                try {
                    JSONObject jsonBody = request.getRequestJson();
                    SystemUtil.println("RequestBody:", jsonBody);
                    if (null != requestBody) {
                        ActionUtil.fillJSONObject(jsonBody, requestBody);
                    }
                    result = response.redirect(new ActionRedirect(request.getMethod(), rp));
                    if (null == result) return;
                    if (result instanceof Exception) {
                        throw (Exception) result;
                    }
                } catch (Exception e) {
                    String error;
                    if (e instanceof RequestExecption) {
                        throw (RequestExecption) e;
                    } else if (e instanceof InvocationTargetException) {
                        Throwable target = ((InvocationTargetException) e).getTargetException();
                        error = target.getMessage();
                    } else {
                        error = e.getMessage();
                    }
                    SystemUtil.println("--------------\r\n", "error:", error, "\turl:", servletPath);
                    throw new RequestExecption(StatusCode.InternalServerError, error);
                }
            }
        }
        if(null==result){
            response.outPath(servletPath);
        }else if(result instanceof ResponseFile){
            ResponseFile r=(ResponseFile) result;
            response.outFile(r.getFile(),r.getType(),r.getDisposition());
        }else if(result instanceof ResponseByte){
            ResponseByte r=(ResponseByte) result;
            response.setHeader(Header.ContentDisposition,r.getDisposition().toString());
            response.out(r.getBs(),r.getType());
        }else{
            response.out(result);
        }
    }
}
